package com.bbs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bbs.config.BBSConfig;
import com.bbs.dto.CommendQuery;
import com.bbs.dto.CommentAdd;
import com.bbs.dto.CommentDto;
import com.bbs.exception.BusinessException;
import com.bbs.feign.UserClient;
import com.bbs.mapper.CommentMapper;
import com.bbs.mapper.PostMapper;
import com.bbs.pojo.Comment;
import com.bbs.pojo.Post;
import com.bbs.pojo.Result;
import com.bbs.pojo.dto.UserDto;
import com.bbs.pojo.dto.message.ReplyMessageContent;
import com.bbs.service.ICommentService;
import com.bbs.utils.MessageSender;
import com.bbs.utils.ObjectUtil;
import com.bbs.utils.SecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment>
        implements ICommentService {
    @Autowired
    CommentMapper commentMapper;
    @Autowired
    PostMapper postMapper;
    @Autowired
    UserClient userClient;
    @Autowired
    MessageSender messageSender;

    public boolean addComment(CommentAdd commentAdd)
            throws Exception {
        Comment comment = new Comment();
        comment.setUserId(SecurityUtil.getCurrentUser().getUserId());
        ObjectUtil.mergeObj(commentAdd, comment);

        if(commentAdd.getReplyTo() != null){
            Comment repliedComment = getById(commentAdd.getReplyTo());
            if(repliedComment == null){
                throw new BusinessException("被回复的评论不存在");
            }

            //设置二级评论的parentId
            if(repliedComment.getParentId() != null){
                //被回复的评论为一个二级评论，指向同一个一级评论
                comment.setParentId(repliedComment.getParentId());
            }else{
                //被回复的评论为一个一级评论，指向该一级评论
                comment.setParentId(repliedComment.getCommentId());
            }

            //发送提示消息给被回复者
            sendReplyMessage(comment, repliedComment);
        }else{
            //发送提示消息给楼主
            sendReplyMessageToPostAuthor(comment);
        }



        //加经验
        userClient.addExperience(SecurityUtil.getCurrentUser().getUserId(), BBSConfig.COMMENT_EXPERIENCE);

        comment.setCreateTime(LocalDateTime.now());
        comment.setUpdateTime(LocalDateTime.now());
        return this.save(comment);
    }

    @Override
    public IPage<Comment> getComments(CommendQuery commendQuery) {
        QueryWrapper<Comment> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("post_id", commendQuery.getPostId());
        queryWrapper.orderByAsc("update_time");

        if(commendQuery.getParentId() != null){
            //查询一级评论为commendQuery.getParentId()的所有评论
            queryWrapper.eq("parent_id", commendQuery.getParentId());
        }else{
            //查询一页一级评论
            queryWrapper.isNull("parent_id");
        }

        IPage<Comment> commentPage = commentMapper.selectPage(new Page<>(commendQuery.getPageNo(), commendQuery.getPageSize()), queryWrapper);
        List<Comment> comments = commentPage.getRecords();

        //查询并缓存所有所需用户信息
        Map<String, UserDto> userId2userDto = new HashMap<>();
        //快速通过评论ID获取其发送者
        Map<String, UserDto> commentId2UserDto = new HashMap<>();
        for (Comment comment : comments) {
            String userId = comment.getUserId();
            UserDto userDto = userId2userDto.get(userId);
            if(userDto == null){
                Result<UserDto> result = userClient.getUser(userId);
                if(result != null){
                    userDto = result.getData();
                }

                if(userDto != null){
                    userId2userDto.put(userId, userDto);
                }
            }

            commentId2UserDto.put(comment.getCommentId(), userDto);
        }

        //组装CommentDto
        List<CommentDto> commentDtos = new ArrayList<>();
        for (Comment comment : comments) {
            CommentDto commentDto = new CommentDto();
            try{
                ObjectUtil.mergeObj(comment, commentDto);
            }catch (Exception e){
                throw new RuntimeException(e);
            }

            commentDto.setUser(commentId2UserDto.get(comment.getCommentId()));
            commentDto.setRepliedUser(commentId2UserDto.get(comment.getReplyTo()));
            commentDtos.add(commentDto);
        }

        IPage commentDtoPage = commentPage;
        commentDtoPage.setRecords(commentDtos);
        return commentDtoPage;
    }

    @Override
    @Transactional
    public boolean deleteComment(String id) {
        Comment comment = new Comment();
        comment.setCommentId(id);
        comment.setUserId(SecurityUtil.getCurrentUser().getUserId());
        boolean flag = remove(new QueryWrapper<>(comment));

        //删除成功
        if(flag){
            //删除子回复
            Comment subComment = new Comment();
            subComment.setParentId(id);
            remove(new QueryWrapper<>(subComment));
        }

        //经验扣除
        userClient.addExperience(SecurityUtil.getCurrentUser().getUserId(), -BBSConfig.COMMENT_EXPERIENCE);

        return flag;
    }

    /**
     * 发送消息给被回复者
     * @param comment
     * @param repliedComment
     */
    private void sendReplyMessage(Comment comment, Comment repliedComment){
        Post post = new Post();
        post.setPostId(repliedComment.getPostId());
        post = postMapper.selectOne(new QueryWrapper<>(post));

        String commentText = comment.getContent();
        commentText = commentText.length() <= 100 ? commentText : commentText.substring(0, 100) + "...";

        ReplyMessageContent messageContent = new ReplyMessageContent();
        messageContent.setComment(commentText);
        messageContent.setPostTitle(post.getTitle());
        messageContent.setPostId(post.getPostId());
        messageContent.setReplierUserId(comment.getUserId());
        messageContent.setReplierUsername(SecurityUtil.getCurrentUser().getUsername());

        messageSender.send(repliedComment.getUserId(), comment.getUserId(), messageContent);
    }

    private void sendReplyMessageToPostAuthor(Comment comment){
        Post post = new Post();
        post.setPostId(comment.getPostId());
        post = postMapper.selectOne(new QueryWrapper<>(post));

        String commentText = comment.getContent();
        commentText = commentText.length() <= 100 ? commentText : commentText.substring(0, 100) + "...";

        ReplyMessageContent messageContent = new ReplyMessageContent();
        messageContent.setComment(commentText);
        messageContent.setPostTitle(post.getTitle());
        messageContent.setPostId(post.getPostId());
        messageContent.setReplierUserId(comment.getUserId());
        messageContent.setReplierUsername(SecurityUtil.getCurrentUser().getUsername());

        messageSender.send(post.getUserId(), comment.getUserId(), messageContent);
    }
}
